package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"runtime"
	"strings"
)

func main() {
	cocos := flag.String("cocos", "", "CocosCreator安装路径")
	plat := flag.String("p", "", "发布平台")
	project := flag.String("path", "", "项目工程位置")
	ename := flag.String("ename", "", "项目名称（英文名称）")
	cname := flag.String("cname", "", "项目名称（中文名称）")
	bundle := flag.String("bundle", "", "IOS包的Bundle Identifier")
	scene := flag.String("scene", "", "主场景的uuid值")
	appid := flag.String("appid", "", "微信开放平台申请的APPID")
	ori := flag.String("orientation", "0", "屏幕方向（0：横屏；1：竖屏）")
	ip := flag.String("ip", "127.0.0.1", "服务器ip地址")
	club := flag.String("club", "0", "俱乐部（0:非；1:俱乐部）")
	privateAppId := flag.String("private_app_id","", "声网APPID")
	flag.Parse()
	checkInput(cocos, plat, project, ename, appid)
	orientation := "{'landscapeLeft': true, 'landscapeRight': true}"
	if *ori == "1" {
		orientation = "{'portrait': true, 'upsideDown': true}"
	}
	system := runtime.GOOS
	var cocoscreator string
	if *plat == "android" {
		if system == "windows" {
			cocoscreator = *cocos + "/CocosCreator.exe"
		} else {
			cocoscreator = *cocos + "/CocosCreator.app/Contents/MacOS/CocosCreator"
		}

		//构建项目
		cmd := exec.Command("/bin/sh", "-c", cocoscreator + " --path " + *project + " --build \"title=" + *ename + ";platform=android;startScene=" + *scene + ";packageName=org.cocos2dx." + *ename+";debug=false;useDebugKeystore=true;orientation="+orientation+";template=binary;apiLevel=android-26;appABIs=['armeabi', 'armeabi-v7a','arm64-v8a','x86'];androidStudio=true\"")
		cmd.Stdout = os.Stdout
		cmd.Stderr = os.Stdout
		err := cmd.Run()
		if err != nil {
			fmt.Println(err)
			fmt.Errorf("构建失败, %s", err.Error())
			os.Exit(1)
		}
		fmt.Println("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<构建成功，准备替换资源>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>")
		exist := existFile(*project + "/build/android_lock")
		if !exist {
			os.Create(*project + "/build/android_lock")
			androidPath := *project + "/build/jsb-binary/frameworks/runtime-src/proj.android-studio"
			appPath := androidPath + "/app"
			resPath := appPath + "/res"
			srcPath := appPath + "/src"
			stringsPath := resPath + "/values/strings.xml"
			resetStringByReg(stringsPath, `<string[\S\s]+?</string>`, "<string name=\"app_name\" translatable=\"false\">" + *cname+"</string>")
			setManifest(appPath, ename)
			renamePackageName(srcPath, ename, appid, privateAppId)
			//复制icon
			copyDir(*project+"/appIcons/android/res", appPath, "android")
		}
		copyDir("./cocos/main.js", *project+"/build/jsb-binary", "android")
		hotupdate(*project, *ip, *club)
		fmt.Println("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<资源替换成功，准备编译>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>")
		cmd = exec.Command("/bin/sh", "-c", cocoscreator + " --path " + *project + " --compile \"title=" + *ename + ";platform=android;startScene=" + *scene + ";packageName=org.cocos2dx." + *ename+";debug=false;useDebugKeystore=true;orientation="+orientation+";template=binary;apiLevel=android-26;appABIs=['armeabi', 'armeabi-v7a','arm64-v8a','x86'];androidStudio=true\"")
		cmd.Stdout = os.Stdout
		cmd.Stderr = os.Stdout
		err = cmd.Run()
		if err != nil {
			fmt.Println(err)
			fmt.Errorf("编译失败, %s", err.Error())
			os.Exit(1)
		}
		fmt.Println("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<编译成功，apk安装包已生成>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>")
	} else if *plat == "ios" {
		if *bundle == "" {
			fmt.Println("未设置IOS包的Bundle Identifier")
			os.Exit(1)
		}
		if system == "windows" {
			fmt.Println("不支持打包苹果ipa安装包")
			os.Exit(1)
		} else {
			cocoscreator = *cocos + "/CocosCreator.app/Contents/MacOS/CocosCreator"
		}

		//构建项目
		cmd := exec.Command("/bin/sh", "-c", cocoscreator + " --path " + *project + " --build \"title=" + *ename + ";platform=ios;startScene=" + *scene+";debug=false;orientation="+orientation+";template=binary;\"")
		cmd.Stdout = os.Stdout
		cmd.Stderr = os.Stdout
		err := cmd.Run()
		if err != nil {
			fmt.Println(err)
			fmt.Errorf("构建失败, %s", err.Error())
			os.Exit(1)
		}
		fmt.Println("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<构建成功，准备替换资源>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>")
		iosPath := *project + "/build/jsb-binary/frameworks/runtime-src/proj.ios_mac"

		exist := existFile(*project + "/build/ios_lock")
		if !exist {
			os.Create(*project + "/build/ios_lock")
			//打开项目，用以生成workspace
			cmd = exec.Command("open", iosPath + "/" + *ename+".xcodeproj")
			cmd.Stdout = os.Stdout
			cmd.Stderr = os.Stdout
			err = cmd.Run()
			if err != nil {
				fmt.Println(err)
				fmt.Errorf("打开项目失败, %s", err.Error())
				os.Exit(1)
			}
			stringsPath := iosPath + "/ios/Info.plist"
			resetStringByReg(stringsPath, `<key>CFBundleDisplayName</key>[\r|\n|\s]+?<string>[\S\s]+?</string>`, "<key>CFBundleDisplayName</key>\r\n\t<string>" + *cname+"</string>")
			resetStringByReg(stringsPath, `<key>CFBundleIdentifier</key>[\r|\n|\s]+?<string>[\S\s]+?</string>`, "<key>CFBundleIdentifier</key>\r\n\t<string>" + *bundle+"</string>")
			resetStringByReg(stringsPath, `<key>CFBundleURLName</key>[\r|\n|\s]+?<string>[\S\s]+?</string>`, "<key>CFBundleURLName</key>\r\n\t<string>" + *bundle+"</string>")
			replaceFileContentWithEname(stringsPath, "hellojavascript", ename)
			replaceFileContentWithEname(iosPath+"/ios/AppController.mm", "hellojavascript", ename)
			if *appid != "" {
				replaceFileContentWithEname(stringsPath, "wx0000000000000000", appid)
				replaceFileContentWithEname(iosPath+"/Wechat.m", "wx0000000000000000", appid)
			}
			copyDir(*project+"/appIcons/ios", iosPath+"/ios", "ios")
			os.Rename(iosPath+"/HelloJavascript-mobile", iosPath + "/" + *ename+"-mobile")
			copyIOSIcon(project, iosPath, ename)
		}
		copyDir("./cocos/main.js", *project+"/build/jsb-binary", "ios")
		hotupdate(*project, *ip, *club)
		fmt.Println("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<资源替换成功，准备编译>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>")
		//cmd = exec.Command("/bin/sh", "-c", cocoscreator+" --path "+*project+" --compile \"title="+*ename+";platform=ios;startScene="+*scene+";debug=false;orientation="+orientation+";template=binary;\"")
		//cmd.Stdout = os.Stdout
		//cmd.Stderr = os.Stdout
		//err = cmd.Run()
		//if err != nil {
		//	fmt.Println(err)
		//	fmt.Errorf("编译失败, %s", err.Error())
		//	os.Exit(1)
		//}
		//fmt.Println("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<编译成功，app包已生成，准备生成archive包>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>")
		//buildPath := *project + "/build/jsb-binary/publish/ios"
		//cmd = exec.Command("/bin/sh", "-c", "xcodebuild archive -workspace "+iosPath+"/"+*ename+".xcodeproj/project.xcworkspace -scheme "+*ename+"-mobile -configuration Release -archivePath "+buildPath+"/"+*ename+".xcarchive")
		//cmd.Stdout = os.Stdout
		//cmd.Stderr = os.Stdout
		//err = cmd.Run()
		//if err != nil {
		//	fmt.Println(err)
		//	fmt.Errorf("生成archive包失败, %s", err.Error())
		//	os.Exit(1)
		//}
		//fmt.Println("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<archive包生成成功，准备导出ipa安装包>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>")
		//cmd = exec.Command("/bin/sh", "-c", "xcodebuild -exportArchive -archivePath "+buildPath+"/"+*ename+".xcarchive -configuration Release -exportPath "+buildPath+" -exportOptionsPlist ./plist/com.options.plist")
		//cmd.Stdout = os.Stdout
		//cmd.Stderr = os.Stdout
		//err = cmd.Run()
		//if err != nil {
		//	fmt.Println(err)
		//	fmt.Errorf("导出ipa失败, %s", err.Error())
		//	os.Exit(1)
		//}
		//fmt.Println("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<ipa安装包导出成功>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>")
	}
}

func existFile(path string) bool {
	_, err := os.Stat(path)
	if err == nil {
		return true
	}
	if os.IsNotExist(err) {
		return false
	}
	return true
}

/**
复制Icon到指定目录中
*/
func copyIOSIcon(project *string, iosPath string, ename *string) {
	copyDir(*project+"/appIcons/ios/Icon-29.png", iosPath + "/" + *ename+"-mobile/Images.xcassets/AppIcon.appiconset", "ios")
	copyDir(*project+"/appIcons/ios/Icon-40.png", iosPath + "/" + *ename+"-mobile/Images.xcassets/AppIcon.appiconset", "ios")
	copyDir(*project+"/appIcons/ios/Icon-58.png", iosPath + "/" + *ename+"-mobile/Images.xcassets/AppIcon.appiconset", "ios")
	copyDir(*project+"/appIcons/ios/Icon-59.png", iosPath + "/" + *ename+"-mobile/Images.xcassets/AppIcon.appiconset", "ios")
	copyDir(*project+"/appIcons/ios/Icon-76.png", iosPath + "/" + *ename+"-mobile/Images.xcassets/AppIcon.appiconset", "ios")
	copyDir(*project+"/appIcons/ios/Icon-80.png", iosPath + "/" + *ename+"-mobile/Images.xcassets/AppIcon.appiconset", "ios")
	copyDir(*project+"/appIcons/ios/Icon-81.png", iosPath + "/" + *ename+"-mobile/Images.xcassets/AppIcon.appiconset", "ios")
	copyDir(*project+"/appIcons/ios/Icon-120.png", iosPath + "/" + *ename+"-mobile/Images.xcassets/AppIcon.appiconset", "ios")
	copyDir(*project+"/appIcons/ios/Icon-152.png", iosPath + "/" + *ename+"-mobile/Images.xcassets/AppIcon.appiconset", "ios")
	copyDir(*project+"/appIcons/ios/Default-568h@2x.png", iosPath + "/" + *ename+"-mobile/Images.xcassets/LaunchImage.launchimage", "ios")
}

func checkInput(cocos *string, plat *string, project *string, ename *string, appid *string) {
	if *cocos == "" {
		fmt.Println("CocosCreator安装路径，请输入参数-cocos=CocosCreator path")
		os.Exit(1)
	}
	if *plat == "" {
		fmt.Println("发布平台未填写，请输入参数-p=ios/android")
		os.Exit(1)
	} else {
		if *plat != "android" && *plat != "ios" {
			fmt.Println("暂不支持的平台")
			os.Exit(1)
		}
	}
	if *project == "" {
		fmt.Println("项目位置路径未填写，请输入参数-path=project path")
		os.Exit(1)
	}
	if *ename == "" {
		fmt.Println("项目名称未填写，请输入参数-name=英文名称")
		os.Exit(1)
	}
	//可不输入，不输入不提供微信登录功能
	if *appid == "" {
		fmt.Println("微信开放平台APPID未填写，请输入参数-wechat=APPID")
		fmt.Println("如果不填写APPID，则无法使用微信登录功能")
	}
}

/**
修改文件中指定的内容为设置的英文名称
*/
func renamePackageName(folder string, ename *string, appid *string, privateAppId *string) {
	//修改路径
	renameFilePath(folder, ename)
	//修改文件内容
	renameFileContent(folder, ename, appid, privateAppId)
}

func renameFilePath(folder string, ename *string) {
	files, _ := ioutil.ReadDir(folder)
	for _, file := range files {
		if file.IsDir() {
			if file.Name() == "txproject" {
				os.Rename(folder+"/"+file.Name(), folder + "/" + *ename)
			}
			renameFilePath(folder+"/"+file.Name(), ename)
		}
	}
}

func renameFileContent(folder string, ename *string, appid *string, privateAppId *string) {
	files, _ := ioutil.ReadDir(folder)
	for _, file := range files {
		if file.IsDir() {
			renameFileContent(folder+"/"+file.Name(), ename, appid, privateAppId)
		} else {
			srcFile := folder + "/" + file.Name()
			replaceFileContentWithEname(srcFile, "txproject", ename)
			if *appid != "" {
				replaceFileContentWithEname(srcFile, "WXEntryActivity_APPID", appid)
			}
			if *privateAppId != "" {
				replaceFileContentWithEname(srcFile, "PRIVATE_APP_ID", privateAppId)
			}
		}
	}
}

/**
设置安卓Manifest文件内容
*/
func setManifest(appPath string, ename *string) {
	manifestPath := appPath + "/AndroidManifest.xml"
	replaceFileContentWithEname(manifestPath, "txproject", ename)
}

/**
将文件中指定的内容以提供的英文名替换
*/
func replaceFileContentWithEname(filePath string, src string, dest *string) {
	buf, err := ioutil.ReadFile(filePath)
	if err != nil {
		fmt.Println("未找到文件，请先构建Cocos构建")
		os.Exit(1)
	}
	content := string(buf)
	newContent := strings.Replace(content, src, *dest, -1)
	//重新写入
	ioutil.WriteFile(filePath, []byte(newContent), 0)
}

/**
设置游戏APP中文名称
*/
func resetStringByReg(stringsPath string, regstr string, dest string) {
	buf, err := ioutil.ReadFile(stringsPath)
	if err != nil {
		fmt.Println("未找到文件，请先构建Cocos构建")
		os.Exit(1)
	}
	content := string(buf)
	reg := regexp.MustCompile(regstr)
	newContent := reg.ReplaceAllString(content, dest)
	//重新写入
	ioutil.WriteFile(stringsPath, []byte(newContent), 0)
}

/**
复制目录到指定位置
*/
func copyDir(src string, dest string, platform string) {
	err := filepath.Walk(src, func(src string, f os.FileInfo, err error) error {
		if f == nil {
			return err
		}
		if f.IsDir() {
		} else {
			var dest_new string
			if platform == "android" {
				if strings.Index(src, "/res") > -1 {
					dest_new = dest + substr(src, strings.Index(src, "/res"), len(src))
				} else {
					dest_new = dest + substr(src, strings.Index(src, "/cocos")+6, len(src))
				}
			} else {
				if strings.Index(src, "/ios") > -1 {
					dest_new = dest + substr(src, strings.Index(src, "/ios")+4, len(src))
				} else {
					dest_new = dest + substr(src, strings.Index(src, "/cocos")+6, len(src))
				}
			}
			fmt.Println(">>>>>>" + dest_new)

			dest_dir := dest_new[:strings.LastIndex(dest_new, "/")+1]
			if strings.Index(src, "DS_Store") > -1 {
				return nil
			}
			fmt.Println("复制:" + src + " 到 " + dest_dir)
			b, _ := pathExists(dest_dir)
			if !b {
				err := os.Mkdir(dest_dir, 0755)
				if err != nil {
					fmt.Println(err)
				}
			}
			copyFile(src, dest_new)
		}
		return nil
	})
	if err != nil {
		fmt.Printf("filepath.Walk() returned %v\n", err)
	}
}

func copyFile(src string, dst string) {
	buf, _ := ioutil.ReadFile(src)
	ioutil.WriteFile(dst, buf, 0755)
}

func pathExists(path string) (bool, error) {
	_, err := os.Stat(path)
	if err == nil {
		return true, nil
	}
	if os.IsNotExist(err) {
		return false, nil
	}
	return false, err
}

func substr(str string, start int, end int) string {
	rs := []rune(str)
	length := len(rs)
	if start < 0 || start > length {
		panic("start is wrong")
	}
	if end < 0 || end > length {
		panic("end is wrong")
	}
	return string(rs[start:end])
}

func hotupdate(projectPath string, ip string, club string) {
	if ip != "127.0.0.1" {
		versionPath := projectPath + "/assets/Script/Global.js"
		buf, err := ioutil.ReadFile(versionPath)
		if err != nil {
			fmt.Println("未找到文件，请先构建Cocos构建")
			os.Exit(1)
		}
		reg1 := regexp.MustCompile("CLIENT_VERSION\\s*=\\s*\"\\d*\\.\\d*\\.\\d*\"")
		byteContent1 := reg1.Find(buf)
		reg2 := regexp.MustCompile("\\d*\\.\\d*\\.\\d*")
		byteContent2 := reg2.Find(byteContent1)
		version := string(byteContent2)
		clubStr := "/"
		if club == "1" {
			clubStr = "/"
		}
		cmd := exec.Command("/bin/sh", "-c", "cd "+projectPath+" && /usr/local/Cellar/node/8.4.0/bin/node version_generator.js -v "+version+" -u http://"+ip+":81"+clubStr+"hotupdate/remote-assets/ -s build/jsb-binary/ -d assets/")
		cmd.Stdout = os.Stdout
		cmd.Stderr = os.Stdout
		err = cmd.Run()
		if err != nil {
			fmt.Println(err)
			fmt.Errorf("热更新配置生成失败, %s", err.Error())
			os.Exit(1)
		}
	}
}
